﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System;
using System.Collections.Generic;
using System.Linq;

namespace BlueCurve.Common.InteractiveConsole
{
    /// <summary>
    /// Fournit les méthodes pour la console interactive
    /// </summary>
    public abstract class BaseConsole
    {

        #region Constructor

        /// <summary>
        /// Constructeur
        /// </summary>
        public BaseConsole()
        {
            Commands = new Dictionary<string, Dictionary<Action, string>>()
            {
                { "help", new Dictionary<Action, string>() { { () => PrintCommands(), "" } } }
            };
            LoadCommands();
        }

        #endregion








        #region Console Properties

        /// <summary>
        /// Nom de l'application
        /// </summary>
        public abstract string Name { get; }

        #endregion







        #region Commands

        /// <summary>
        /// Commandes d'arrete par défaut de lapplication
        /// </summary>
        protected static readonly string[] exitCommands = new string[] { "-q", "-exit", "-quit" };

        /// <summary>
        /// Donctionnaire contenant les commandes, ainsi que les actions et
        /// leur description
        /// </summary>
        public Dictionary<string, Dictionary<Action, string>> Commands
        {
            get;
            protected set;
        }

        /// <summary>
        /// Fonction de chargement des commandes
        /// </summary>
        protected abstract void LoadCommands();

        #endregion







        #region Command Processing

        /// <summary>
        /// Traitement des commandes
        /// et exécution de l'action associée
        /// </summary>
        /// <param name="cmd">Commande de l'utilisateur</param>
        protected virtual void ProcessCommand(string cmd)
        {
            Dictionary<Action, string> action = null;
            if (Commands.TryGetValue(cmd, out action))
            {
                foreach (KeyValuePair<Action, string> pair in action)
                    pair.Key();
            }
            else
            {
                Console.WriteLine("Unknown command");
            }
        }

        /// <summary>
        /// Affichage des commandes
        /// </summary>
        private void PrintCommands()
        {
            Console.WriteLine("Available Commands:");
            foreach (KeyValuePair<string, Dictionary<Action, string>> a in Commands)
            {
                foreach (KeyValuePair<Action, string> pair in a.Value)
                {
                    Console.WriteLine("\t" + a.Key + " > " + pair.Value);
                }
            }
        }

        #endregion








        #region Run

        /// <summary>
        /// Fonction principale
        /// </summary>
        public void Run()
        {
            Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            Console.InputEncoding = System.Text.Encoding.UTF8;
            Console.BufferHeight = 1024;
            Console.BufferWidth = 1024;

            Console.WriteLine(Name);
            Console.WriteLine("=====================================");
            Console.WriteLine("Type 'help' to get available commands");
            Console.WriteLine();

            Console.Write(">>");
            string input = Console.ReadLine();

            // While not exit command entered, process each command
            while (!exitCommands.Contains(input, StringComparer.CurrentCultureIgnoreCase))
            {
                try
                {
                    // process command
                    ProcessCommand(input);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                finally
                {
                    Console.WriteLine();
                    Console.Write(">>");
                    input = Console.ReadLine();
                }
            }
        }

        /// <summary>
        /// Fonction attaché au l'applie sur CTRL+C
        /// </summary>
        private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Bad exit of the application, datas may lost");
            System.Diagnostics.Process.GetCurrentProcess().Kill();
        }

        #endregion
    }
}
